A Little Symlink Confusion

The ln coreutil primarily uses the system calls link, syslink, and the *at versions of each. If ln is strace'd while making a symbolic link, the important part of the output is just that:

symlinkat("a", AT_FDCWD, "b")           = 0

However, if the target already exists (and you've specified -f to overwrite the output) strace tells a little bit of a different story:

getrandom("\x0a\x5d\x59\xc2\x73\x80\x90\xe2", 8, GRND_NONBLOCK) = 8
symlinkat("a", AT_FDCWD, "CuCrcPHI")    = 0
renameat(AT_FDCWD, "CuCrcPHI", AT_FDCWD, "b") = 0

A simple call to symlinkat will not overwrite the existing link. Instead, ln makes a new file with a random name and moves it onto the target.

The difference is subtle, but occaisonally important. Filesystem monitoring API's in particular will generally distinguish between creating a file and overwriting that same file with a rename. If a directory is watched, with, for instance, inotify, watching only for IN_CREATE will suffice for plenty of cases, but fail to catch ln -sf. The fix is certainly not too onerous; you'll just need to watch for IN_MOVED_TO events as well.

Neither the problem nor the solution are particularly exciting, but the core of the issue --- that ln -sf involved a call to a random number genarator --- certainly surprised me!

a teapot websitevalid html 2.0!